package com.scy.edu;

import com.scy.edu.client.RpcConsumer;
import com.scy.edu.service.UserService;
import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.ZkClient;
import org.apache.zookeeper.data.Stat;

import java.util.*;

/**
 * @author 司晨雨
 * @date 2020/8/20 23:04
 * @description
 */
public class ConsumerBoot {
    //缓存服务注册信息
    private volatile static Map<String,Object> zkMap = new HashMap<String,Object>();
    //zk实例
    private static ZkClient zkClient;

    public static void main(String[] args) throws InterruptedException {
        zkClient = new ZkClient("127.0.0.1:2181");
        //加载zk服务注册信息
        getServerInfo();
        while (true){
            List<String> errorServices = new ArrayList();
            String port = selectServerPort();
            String address = (String)zkMap.get(port);
            RpcConsumer rpcConsumer = new RpcConsumer(address, Integer.parseInt(port));
            UserService userService = (UserService) rpcConsumer.createProxy(UserService.class);
            String result;
            String serviceName = address+":"+port;
            try{
                //调用服务
                result = userService.sayHello(serviceName);
            }catch (Exception e){
                //异常则说明服务不通或已下线
                result = "exception";
            }
            System.out.println(serviceName+"调用结果为"+result);
            if("exception".equals(result) || "timeout".equals(result)){
                errorServices.add(serviceName.split(":")[1]);
                System.out.println("服务名:"+serviceName+"调用服务异常,停止调用,等待zk下线改地址");
            }
            zkClient.writeData("/lgServer/"+serviceName,"");
            //服务下线时将customMap中的服务端代理移除,当zk延迟感应到服务下线时,会重新获取服务信息,就会更新zkMap,同时也会更新customMap
            for (String errorService : errorServices) {
                zkMap.remove(errorService);
            }
            Thread.sleep(2000);
        }
    }

    //分配服务器
    public static String selectServerPort(){
        ZkClient zkClient = new ZkClient("127.0.0.1");
        //服务器数量
        if(zkMap.size() >1){//目前两台做比较
            //节点信息
            Stat stat1 =new Stat();
            Object data1 = zkClient.readData("/lgServer/127.0.0.1:8888", stat1);
            Stat stat2 =new Stat();
            Object data2 = zkClient.readData("/lgServer/127.0.0.1:9999", stat2);
            if(data1 == null || data1.equals("") || data2.equals("")  || data2 ==null){
                return getServerPort();
            }else{
                Long requestTime1 = Long.valueOf(String.valueOf(data1));
                Long responseTime1 = Long.valueOf(String.valueOf(stat1.getMtime()));
                long time1 =responseTime1-requestTime1;
                System.out.println("server1"+stat1.getMtime());
                Long requestTime2 = Long.valueOf(String.valueOf(data2));
                Long responseTime2 = Long.valueOf(String.valueOf(stat2.getMtime()));
                long time2 =responseTime2-requestTime2;
                System.out.println("server2"+stat2.getMtime());
                if(time1==time2){//响应时间相同
                    return getServerPort();
                }else if(time1 <time2){
                    return "8888";
                }else {
                    return "9999";
                }
            }
        }else{
            return getServerPort();
        }
    }

    public static String getServerPort(){
        // 获取集群服务器数量
        List<String> portList = new ArrayList<String>(zkMap.keySet());
        Random random = new Random();
        int num = random.nextInt(portList.size());
        String serverPort = portList.get(num);
        return serverPort;
    }

    //获取服务注册信息
    private static void getServerInfo(){
        //获取服务列表
        List<String> servicesList = zkClient.getChildren("/lgServer");
        //添加监听,用于发现服务
        zkClient.subscribeChildChanges("/lgServer", new IZkChildListener() {
            public void handleChildChange(String serviceName, List<String> list) throws Exception {
                System.out.println("------获取注册服务信息----");
                getServerInfo();//重新获取注册信息
            }
        });
        //从各个服务节点下获取IP地址
        for (String addressInfo : servicesList) {
            String[] serverStrings = addressInfo.split(":");
            String host =serverStrings[0];
            int port =Integer.parseInt(serverStrings[1]);
            System.out.println("server号："+host+":"+port);
            zkMap.put(port+"",host);
        }
        System.out.println(zkMap);

    }
}
